#include <iostream>
#include <sys/socket.h> // 主要socket函数和结构
#include <netinet/in.h> // IPv4/IPv6地址结构
#include <arpa/inet.h>  // 地址转换函数(如inet_pton)
#include <unistd.h>     // close()函数
#include "nocpy.hpp"
#include <cstring>
#include "Log.hpp"
#include "InetAddr.hpp"
enum
{
    SOCKET_ERROR = 1,
    BIND_ERROR
};
class UdpServer : public nocopy // 继承的特性，拷贝构造和赋值构造被ban
{
public:
    UdpServer(uint16_t localport) : _localport(localport)
    {
    }
    void Init()
    {
        // 1.创建socket文件
        _sockfd = ::socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(FATAL, "socket error");
            exit(SOCKET_ERROR);
        }
        LOG(DEBUG, "socket create success");
        // 2.bind
        struct sockaddr_in local; // 因为是网络间通信，所有设置为sockadr_in
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_localport); // 从主机字节序转换为网络字节序。
        //local.sin_addr 是一个 struct in_addr 类型，它内部有一个 s_addr 成员（uint32_t 类型），存储的是 ​​网络字节序的 IPv4 地址​​。
        // local.sin_addr.s_addr = inet_addr(_localip.c_str());//将 IPv4 点分十进制字符串（如 "192.168.1.1"）转换为 32 位网络字节序的整数（uint32_t）
        local.sin_addr.s_addr = INADDR_ANY; // 0
        // inet_addr()也会改为网络字节序

        int n = ::bind(_sockfd, (struct sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "socket bind error");
            exit(BIND_ERROR);
        }
        LOG(DEBUG, "socket bind success");
    }
    void Start()
    {
        _isrunning = true;
        char getmessage[1024];
        while (_isrunning)
        {
            // 收信息
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t n = recvfrom(_sockfd, &getmessage, sizeof(getmessage) - 1, 0, (struct sockaddr *)&peer, &len);
            // 发信息,此时peer被填充好客户端的数据
            if (n > 0)
            {
                LOG(DEBUG, "服务器接收消息成功\n");
                getmessage[n] = 0;   // 给收到的字符串+ \0
                // 打印客户端的ip和端口号
                InetAddr add(peer);
                uint16_t port = add.Port(); 
                std::string ip = add.Ip();
                //std::string echo_string = "[udp_server echo] #";
                std::string echo_string = "[IP:"+ ip +"|||" + "PORT:";
                std::string echo_string1 = "]:";
                //echo_string += getmessage;
                // echo_string.append(getmessage, n);
                std::cout << echo_string <<port<<echo_string1<<getmessage<< std::endl;
                // 会往客户端回显，所以客户端不仅要向服务器发信息，还要接收客户端的回显
                ssize_t num = sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, (struct sockaddr *)&peer, len);
                if (num > 0)
                {
                    LOG(DEBUG, "服务器发送消息成功\n");
                }
                else
                {
                    LOG(DEBUG, "服务器发送消息失败\n");
                }
            }
            else
            {
                LOG(DEBUG, "服务器接收消息失败\n");
            }
        }
    }
    ~UdpServer()
    {
        ::close(_sockfd);
    }

private:
    int _sockfd;         // socket文件描述符，与os交互的端口，通过系统调用申请
    uint16_t _localport; // 16位端口号
    // std::string _localip;//32为ip
    bool _isrunning = false;
};